/*
 * Copyright 2011 Clean GWT
 * 
 * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except
 * in compliance with the License. You may obtain a copy of the License at
 * 
 * http://www.apache.org/licenses/LICENSE-2.0
 * 
 * Unless required by applicable law or agreed to in writing, software distributed under the License
 * is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express
 * or implied. See the License for the specific language governing permissions and limitations under
 * the License.
 */
package com.cleangwt.web.client;

import java.util.List;

import com.cleangwt.json.client.CollectionDeserializer;
import com.cleangwt.json.client.SimpleObject;
import com.cleangwt.json.client.SimpleObjectSerializer;
import com.cleangwt.user.client.ui.RequiresOptions;
import com.cleangwt.user.shared.Option;
import com.cleangwt.user.shared.OptionDeserializer;
import com.google.gwt.event.logical.shared.ValueChangeEvent;
import com.google.gwt.event.logical.shared.ValueChangeHandler;
import com.google.gwt.http.client.RequestBuilder;
import com.google.gwt.user.client.ui.HasValue;

/**
 * This class provides methods for retrieving remote options.
 * 
 * @author Jess
 * @version 1.0
 * @since 1.0
 * 
 */
public class RemoteOptions {

  /**
   * Given the option provider url, the {@link RequiresOptions}, the {@link HasValue} input toggle
   * and the criteria. When the value of toggle is changed, retrieve options via url and set it to
   * the client that requires the options.
   * 
   * @param url the url to invoke remote service
   * @param requiresOptions the client requires options
   * @param toggle the toggle to fire request
   * @param hasCriteria the criteria provider
   */
  public static void bind(final String url, final RequiresOptions requiresOptions,
      HasValue<String> toggle, final ProvidesCriteria hasCriteria) {

    toggle.addValueChangeHandler(new ValueChangeHandler<String>() {

      @Override
      public void onValueChange(ValueChangeEvent<String> event) {
        SimpleObject criteria = hasCriteria.getCriteria();
        if (criteria.values().contains(null)) {
          requiresOptions.setOptions(null);
        } else {
          Requests.send(url, RequestBuilder.POST, SimpleObjectSerializer.get().serialize(
              hasCriteria.getCriteria()), new StatedCallback() {

            @Override
            protected void onSuccess(String result) {
              requiresOptions.setOptions((List<Option>) CollectionDeserializer.get(
                  OptionDeserializer.get()).deserialize(result));
            }

          });
        }
      }
    });
  }

  /**
   * Given the option provider url, the {@link RequiresOptions}, the {@link HasValue} input toggle
   * and the toggle name to make up criteria. When the value of toggle is changed, retrieve options
   * via url and set it to the client that requires the options.
   * 
   * @param url the url to invoke remote service
   * @param requiresOptions the client requires options
   * @param toggle the toggle to fire request
   * @param toggleName the toggle name to make up criteria
   */
  public static void bind(final String url, RequiresOptions requiresOptions,
      final HasValue<String> toggle, final String toggleName) {
    bind(url, requiresOptions, toggle, new ProvidesCriteria() {

      @Override
      public SimpleObject getCriteria() {
        SimpleObject criteria = new SimpleObject();
        criteria.put(toggleName, toggle.getValue());
        return criteria;
      }
    });
  }

  /**
   * Retrieves {@link Option}s via the specified url for the {@link RequiresOptions}.
   * 
   * @param url the url to invoke remote service
   * @param requiresOptions the client requires options
   */
  public static void get(String url, RequiresOptions requiresOptions) {
    get(url, requiresOptions, null);
  }

  /**
   * Retrieves options via the specified url with the given criteria for the {@link RequiresOptions}
   * .
   * 
   * @param url the url to invoke remote service
   * @param requiresOptions the client requires options
   * @param criteria the parameters
   */
  public static void get(String url, final RequiresOptions requiresOptions, SimpleObject criteria) {
    Requests.postObject(url, criteria, new StatedCallback() {

      @Override
      protected void onSuccess(String result) {
        requiresOptions.setOptions((List<Option>) CollectionDeserializer.get(
            OptionDeserializer.get()).deserialize(result));
      }
    });
  }

}
